20180913 畫出K線圖和KD值
這次代碼超長,也需要用前一節代碼,也需要用到很多新模組。
0.導入模組
- tqdm: 跑進度條的模組
- mpl_finance: 畫蠟燭圖 (上一節有解釋)
- talib: 畫KD圖,這是在python一個技術分析模組 (pip3 install ta-lib),通常pip安裝會遇到問題,請到此網址https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib ,找到"正確"的版本,,到whl檔案所在目錄自行安裝 (pip3 install xxxxxxxxx.whl ) ,如果失敗通常是python的版本跟你想的不一樣。
- matplotlib.gridspec: 要將多張圖化在一起使用的模組
- matplotlib.ticker: 將x軸標籤化會使用
#導入模組
import pandas as pd
from datetime import datetime
import time
from tqdm import tqdm
import numpy as np
import mpl_finance as mpf
import matplotlib.gridspec as gridspec
import matplotlib.ticker as ticker
import matplotlib.pyplot as plt
1.抓取個股日成交資訊
首先我們一樣要抓取個股的日成交的資訊,這次用input的方式,
因為上市和上櫃的html的網址位置不同,我們用try/except的方法把這部分補完。
先試抓證交所的資料(try),如果沒有就走櫃買的資料(except)
#帶出現在月份
date = datetime.now()
day = int(int(str(date)[8:10]))
month = int(int(str(date)[5:7]))
if day<=4: #如果月初(又剛好是假日)可能沒資料,我們把月份減一個月來收資料
month = int(int(str(date)[5:7]))-1
#個股代碼
stockno = input('請輸入股票代碼: ')
#設定空df:table / 迴圈預設值m=1 / process bar(進度條 pbar)
table = pd.DataFrame()
m=1
pbar = tqdm(total = month)
#上市走try,上櫃走except
try:
pd.read_html('http://www.twse.com.tw/exchangeReport/STOCK_DAY?response=html&date=20180'+str(month-1)+'01&stockNo='+str(stockno))[0]
while m<=month:
df = pd.read_html('http://www.twse.com.tw/exchangeReport/STOCK_DAY?response=html&date=20180'+str(m)+'01&stockNo='+str(stockno))[0]
df.columns=['日期','成交股數','成交金額','開盤價','最高價','最低價','收盤價','漲跌價差','成交筆數']
table = pd.concat([table,df],ignore_index=True)
m += 1
time.sleep(1) #讓每次抓取間隔1sec,跑太快會被證交所封鎖ip
pbar.update(1) #update進度條
except:
while m<=month:
df = pd.read_html('http://www.tpex.org.tw/web/stock/aftertrading/daily_trading_info/st43_print.php?l=zh-tw&d=107/'+str(m)+'&stkno='+str(stockno))[0]
df.columns=['日期','成交股數','成交金額','開盤價','最高價','最低價','收盤價','漲跌價差','成交筆數']
df = df.drop(df.index[-1:])
table = pd.concat([table,df],ignore_index=True)
m += 1
time.sleep(1) #讓每次抓取間隔1sec,跑太快會被證交所封鎖ip
pbar.update(1) #update進度條
pbar.close() #關閉進度條
#將df:table的日期轉成西元年
table['日期'] = table.apply(lambda x: x['日期'].replace(x['日期'][0:3],str(int(x['日期'][0:3])+ 1911)), axis=1)
table['日期'] = pd.to_datetime(table['日期'])
以2330為例,table的輸出會長這樣:
2.將資料轉換成所需要的格式
蠟燭圖只能吃array的格式,我們要將dataframe轉換成array,
除此之外為了將某些日期資料空白(休市)去掉,
我需要將時間資料標籤化成非時間格式(ex:1,2,3....),待做圖時才將標籤"名稱"轉成時間。
#建立一個新的df:data只取出talib需要的資料取出
data = table[['日期','開盤價','收盤價','最高價','最低價','成交股數']]
data.columns=['date','open','close','high','low','volume'] #重新命名欄位的名稱
#將資料取成array for做圖使用
date_tickers=data.date.values #取出時間標籤的array
#將原df的時間資料修改成 1,2,3.....的array (空白資料
quotes=np.array([tuple([i]+list(quote[1:])) for i,quote in enumerate(data.values)])
#定義function
#將標籤從1,2,3....轉回日期
def format_date(x,pos=None):
if x<0 or x>len(date_tickers)-1:
return ''
return data['date'].iloc[int(x)].strftime('%Y-%m-%d')
#設定x軸:週期為20個資料/將1,2,3....轉回日期
def set_ticker(axes):
axes.xaxis.set_major_locator(ticker.MultipleLocator(20)) #設置主座標的刻度週期
axes.xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) #設置主座標的標籤格式
3.做圖
我打算將蠟燭圖、成交量、KD值,繪製在一張圖表 (將使用到matplotlib.girdspec),
會先用gridspec給定一個框,在分別定義三張圖表的位置和內容 (以ax1,ax2,ax3表示)
其中會用到Talib的語法可以參考官方的document:http://mrjbq7.github.io/ta-lib/funcs.html
外框
fig = plt.figure(figsize=(15,8)) #先圖的外框一個大小 (單位為英寸)
gs = gridspec.GridSpec(4,1) #使用gridspec劃成幾等分的gird,其中(4,1)代表4列1欄
K線圖(蠟燭圖)+MA20
ax1= plt.subplot(gs[0:2,:]) #ax1的在grid裡的範圍,[0:2,:]表示 0~2列整欄
mpf.candlestick_ochl(ax1, quotes, width=0.7, colorup = 'r', colordown = 'g') #畫蠟燭圖(只能用array)
ax1.plot(talib.SMA(data['close'], timeperiod=20),alpha=0.6) #使用Talib來畫MA20
ax1.set_ylabel('Price') #設定Y座標名稱
ax1.set_xlabel('') #設定X座標名稱
ax1.set_title('stock no:'+stockno,size=10) #設定圖表名稱
set_ticker(ax1) #用前面定義的set_ticker這個function來做座標轉換
成交量
ax2= plt.subplot(gs[2,:],sharex=ax1) #ax2的範圍(sharex=ax1代表與ax1共用x軸)
plt.bar(quotes[:,0], data['volume'], width= 0.5) #畫成交量bar chart (x軸為quotes這個array的第1欄,
ax2.set_ylabel('Volume') #設定Y座標名稱
plt.setp(ax2.get_xticklabels(), visible=False) #隱藏ax2 x軸
set_ticker(ax2) #用前面定義的set_ticker這個function來做座標轉換
KD圖 (STOCHSLOW)
ax3= plt.subplot(gs[3,:],sharex=ax1) #ax3的範圍(共用x軸)
#抓出KD的值(K與D各為一組Series)
slowk, slowd = talib.STOCH(data['high'], data['low'], data['close'], fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
ax3.plot(quotes[:,0],slowk) #畫K值
ax3.plot(quotes[:,0],slowd) #畫D值
ax3.set_ylabel('KD') #設定Y座標名稱
ax3.set_xlabel('Date') #設定Y座標名稱
set_ticker(ax3) #用前面定義的set_ticker這個function來做座標轉換
plt.setp(ax3.get_xticklabels(), visible=False) #隱藏ax3 x軸
plt.show() #show圖